1

React Router

文档已经过时! 请查看最新版本 http://rackt.github.io/react-router/

原文: https://github.com/rpflorence/react-router/blob/master/README.md


为 React 定制的完整 routing 模块.

功能

  • 嵌套的 View 映射到嵌套的 Routes
  • route 层级模块化的建构
  • 完全异步的 transition 钩子
  • transition 的 abort / redirect / retry
  • 动态的片段
  • Query 参数
  • 当路由被激活时, 自动给 Links 加 .active class
  • 多个顶级 routes
  • Hash 或者 HTML5 历史的 url

查看 examples 目录来了解前面复杂的 UI 和工作流是怎么创建的.

安装

shnpm install react-nested-router
# or
bower install react-router

这个模块是用 CommonJS 模块写的, 如果你是用 Browserify, Webpack, 这之类的,
你可以当作是其他从 npm 安装的模块一样处理.

在 Bower 上还有一个 UMD 构建的版本, 通过 window.ReactRouter 引用模块.

用法

var Route = require('react-nested-router').Route;

React.renderComponent((
  <Route handler={App}>
    <Route name="about" handler={About}/>
    <Route name="users" handler={Users}>
      <Route name="user" path="/user/:userId" handler={User}/>
    </Route>
  </Route>
), document.body);

如果 JSX 对你来说不算美味的话:

jsReact.renderComponent((
  Route({handler: App},
    Route({name: "about", handler: About}),
    Route({name: "users", handler: Users},
      Route({name: "user", path: "/user/:userId", handler: User})
    )
  )
), document.body);
  • url 会被映射到最深的 route, 随后所有上方层级的 routes 会被激活,
    对应的 handlers(等同 React components)会被渲染.

  • 每个 handler 会接收到一个 params 属性, 包含从 url 中匹配到的参数, 比如 :userId.

  • handler 还好收到一个 query 属性, 是当前的 query 参数的词典.

  • 父级的 routes 会接收到一个 activeRouteHandler 属性, 是一个函数, 用来渲染激活的子元素.

应用的其余部分是这样的:

jsvar Link = require('react-nested-router').Link;

var App = React.createClass({
  render: function() {
    return (


<div>
        <ul>
          <li><Link to="about">About</Link></li>
          <li><Link to="users">Users</Link></li>
          <li><Link to="user" userId="123">User 123</Link></li>
        </ul>
        <this.props.activeRouteHandler/>
      </div>


    );
  }
});

var About = React.createClass({
  render: function() {
    return 

<h2>About</h2>

;
  }
});

var Users = React.createClass({
  render: function() {
    return (


<div>
        <h2>Users</h2>
        <this.props.activeRouteHandler/>
      </div>


    );
  }
});

var User = React.createClass({
  render: function() {
    return 

<div>{this.props.params.userId}</div>


  }
});

要更好地理解 activeRouteHandler 做了什么, 也许一个没有 router 的例子会有用.
比如某个场景 /users/2 被选中, 你不用 router 来渲染, 看起来像是这样:

jsrender: function() {
  var user = <User params={{userId: 2}}/>;
  var users = <User activeRouteHandler={user}/>;
  return <App activeRouteHandler={users}/>;
}

而 router 可以帮你管理 view 的层级关系.

这个方案的好处

  1. 惊人的创建页面的生产力 - 用户访问 route 只有一个场景: 渲染.
    每个 UI 都有 layer(或者嵌套), 可能是简单的导航栏, 或者多层的主从结构.
    把嵌套的 routes 和对应嵌套的 View 耦合在一起, 减去了很多切换过程中两者纠缠的工作.
    添加新的页面就更快了.

  2. 快速理解应用结构 - 当 routes 是在一个地方写清楚的, 开发者很快能从整体看清全局.
    这像是一个基础的 sitemap. 别的办法也没法把应用的那么多信息展示得更快了.

  3. 代码的可操作性 - 当有其他的开发者来修复某个 url 的 bug, 他只要做:
    1) 看懂 route 的设置, 2) 找到对应 route 的 handler.
    每个应用的入口都会在这些 routes 当中展示出来.

  4. url 是你第一件想的事情, 而不是回头想的事情 - 借助 React 嵌套的 router,
    配置 url 以前你是不会得到那么一个页面的. 幸运的是, 这个方案开发小略非常高.

相关的模块

API

Route (component)

配置 component, 声明应用的 routes 和 View 的层级.

Props(属性)

location - 这个方法用在初始化 router 时页面的导航.

可以是 "hash" 表示在 url 当中使用 hash 并监听 hashchange 事件,
或者 "history" 表示使用 HTML5 History API.
这个属性只能在宣染尽页面的第一层的 route 当中使用.
默认值是 "hash".

name - route 的名字, 在 Link component 和 router 的 transition 方法当中使用.

path - 在 url 当中使用的 path, 支持动态生成的片段.
如果这个属性没有被定义(undefined), 这个 path 将会被定义为 name 的值.
这个 path 永远是绝对路径, 即便开头的斜线 / 没有加上.
嵌套的 routes 不会从父级继承 path 的内容.

handler - 当 route 匹配时会被渲染的 component.

子元素

routes 是可以嵌套的. 当子级的 route 匹配了,
父级 route 的 handler 会有个子级 route 的 handler 的实例,
可以通过 this.props.activeRouteHandler() 调用.
你可以在父级当中渲染, 可以传入任何额外需要的属性.

例子
xml<Route handler={App}>
  <!-- path 被自动赋值到 name 上, 因为 name 省略了 -->
  <Route name="about" handler={About}/>
  <Route name="users" handler={Users}>
    <!-- note the dynamic segment in the path -->
    <!-- 注意 path 当中的动态片段 -->
    <Route name="user" handler={User} path="/user/:id"/>
  </Route>
</Route>

或者不用 JSX:

jsRoute({handler: App},
  Route({name: 'about', handler: About}),
  Route({name: 'users', handler: Users},
    Route({name: 'user', handler: User, path: '/user/:id'})
  )
);

Route Handler (用户定义的 component)

传给 route 的 handler 属性的另一个 component, 当 route 被激活时会渲染到页面上.
这些 components 上会有一些特殊的属性和一些静态的方法.

Props(属性)

this.props.activeRouteHandler(extraProps) - 活跃的子节点的 route handler.
在渲染方法当中通过这个渲染子级的 route, 传入额外需要的参数.

this.props.params - 当 route 中存在形如 <Route path="users/:userId"/> 的动态片段,
这些动态的数据就可以在比如 this.props.params.userId 当中吊桶.

this.props.query - url 的 query 参数.

静态方法 (transition 的钩子)

你可以在 route handlers 上定义静态方法, 方法将在 route 的 transition 进行时被调用.

willTransitionTo(transition, params) - 在 route 即将被渲染时调用.
这样你有有机会去中止 transition 过程.
你也可以返回一个 promise, 这样整个 route 层级在继续执行前会先等待 promise 被完成.
这一点对服务端渲染非常有用, 你会需要在 handler 被渲染前构建一些数据.

willTransitionFrom(transition, component) - 在 route transition 开始时调用,
这样就有机会去中止 transition.
这里的 component 是当前的 component, 你可能会需要检查 state 来决定是否运行 transition.

Transition (对象)

transition.abort() - 中止 transition

transition.redirect(to, params, query) - 重定向到另一个 route

transition.retry() - 重试某个 transition

例子
jsvar Settings = React.createClass({
  statics: {
    willTransitionTo: function(transition, params) {
      return auth.isLoggedIn().then(function(loggedIn) {
        if (!loggedIn)
          return;
        transition.abort();
        return auth.logIn({transition: transition});
        // in auth module call `transition.retry()` after being logged in
      });
    },

    willTransitionFrom: function(transition, component) {
      if (component.formHasUnsavedData())) {
        if (!confirm('You have unsaved information, are you sure you want to leave this page?')) {
          transition.abort();
        }
      }
    }
  }

  //...
});

Link (Component)

创建一个锚点元素, 链接到应用的一个 route. 当 route 匹配时自动增加 active class.
如果你改变 route 的 path, 不一定要改变你写的 links.

Properties(属性)

to - 链接的到的 route 的名字.

query - 对象, 添加到 link 上的 query 参数.
从 route handler 上通过 this.props.query 来访问 query 参数.

[param] - route 定义时传入的任何参数会被传入 link 的属性.

例子

当 route 是 <Route name="user" path="/users/:userId"/>:

xml<Link to="user" userId={user.id} params={{foo: bar}}>{user.name}</Link>
<!-- 根据 route 是否被激活, router 变成其中的一个 -->
<a href="/users/123?foo=bar" class="active">Michael</a>
<a href="#/users/123?foo=bar">Michael</a>

顶层的静态方法

router 有几个顶层的方法可以用来对应用进行导航.

jsvar Router = require('react-nested-router')

transitionTo(routeName, [params[, query]]) - 通过程序 transition 到新的 route.

jsRouter.transitionTo('user', {id: 10}, {showAge: true});
Router.transitionTo('about');

replaceWith(routeName, [params[, query]]) - 通过程序把当前的 route 替换为新的 route.
但是不在浏览器的历史里增加记录.

jsRouter.replaceWith('user', {id: 10}, {showAge: true});
Router.replaceWith('about');

goBack() - 通过程序返回前一个 route 并从浏览器历史记录删去最近的一条记录.

jsRouter.goBack();

开发

查看 CONTRIBUTING

感谢 Ember

这个模块很大程度上收到 Ember.js router API 的启发.
一般来说, 这是个 Ember router API 在 React 当中的一个翻译.
深深感谢 Ember 团队他们已经把最难的部分解决了.


题叶
17.3k 声望2.6k 粉丝

Calcit 语言作者